package FlowGram.Application.CommandHost.FinchActionListeners;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.StringTokenizer;

import javax.swing.JDialog;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;

import FlowGram.Application.Application;
import FlowGram.Application.IDEWindow.FileHost.CodeEditor;
import FlowGram.Application.IDEWindow.FileHost.FlowEditor;
import FlowGram.Application.Parser.FinchProgramFlow;
import FlowGram.Application.Parser.Actions.FinchAction;
import FlowGram.Application.Parser.Actions.Move;
import FlowGram.Application.Parser.Actions.TurnLeft;
import FlowGram.Application.Parser.Actions.TurnRight;
import FlowGram.Application.Parser.Actions.Control.ControlAction;
import FlowGram.Application.Parser.Actions.Control.FunctionDefinition;

public class FinchActionListener extends JDialog  implements ActionListener {

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	public static void addCodeTop(FinchAction fa){
		FinchProgramFlow pf = Application.getInstance().getMainWindow().getFileHost().getCurrentCodeFile().getProgramFlow();
		pf.insertActionAt(0, fa);
		updateEditors(pf);
	}
	
	public static void addCode(FinchAction fa){
		FinchProgramFlow pf = Application.getInstance().getMainWindow().getFileHost().getCurrentCodeFile().getProgramFlow();
		CodeEditor codeEditor = (CodeEditor)Application.getInstance().getMainWindow().getFileHost().getCurrentCodeFile().getFileTabbedPane().getComponent(0);
		String allCode = pf.toCode();
		System.out.println("allCode:\n" + allCode);
		int caret = codeEditor.getCaretPosition();
		
		if(caret == 0 ){
			pf.insertActionAt(0, fa);
			updateEditors(pf);
			return;
		}
		
		if(caret == allCode.length()-1){
			pf.insertActionAt(pf.size(), fa);
			updateEditors(pf);
			return;
		}
		
		allCode = replaceTabs(allCode);
		allCode = replaceNewLines(allCode);
		System.out.println("postEdit allCode:\n" + allCode);
//		if(caret == allCode.length()){
//			allCode = allCode.substring(0, caret);
//		}else{
//			allCode = allCode.substring(0, caret+1);
//		}
		
		insertCode(allCode, 0, fa, pf, caret);
		
		
		updateEditors(pf);
	}
	/*
	 * int i used to track the FA on stack
	 */
	private static void insertCode(String allCode, int i, FinchAction fa, FinchProgramFlow pf, int offset){
		System.out.println("traversing\n"+allCode + "|");
		boolean isControl = false;
		int innerCounter = 0;	//find the right FA inside control
		String segment = "";
		int index = 0;
		int beg = 0;
		String cutCode = allCode;
		
		while(true){
			if(index >= offset){
				offset = index - beg;
				System.out.println("hit caret: " + offset);
				break;
			}
			
			System.out.println("cutCode: " + cutCode);
			String line = cutCode.substring(0, cutCode.indexOf("#")+1);
			index += line.length();
			System.out.println("line: " + line);
			System.out.println("index: " + index + "|offset: "+offset+ "|i = "+i);
			if(line.contains("begin ")||
					line.contains("repeat ")||
					line.contains("if ")||
					line.contains("while ")
					){
//				insertCode(allCode.substring(index, offset), ((ControlAction)pf.getActionAt(i)).getInnerFlow().size(), fa, ((ControlAction)pf.getActionAt(i)).getInnerFlow(), offset);
				System.out.println("isControl = true;");
				beg = index;
				isControl = true;
			}
			
			
			if(line.contains("end")){
				System.out.println("isControl = false;");
				isControl = false;
				i++;
				innerCounter++;
				beg = 0;
			}
			
			if(!isControl){
				if(innerCounter >0 && line.contains(
						getEnd(pf.getActionAt(innerCounter-1)))){
	//				System.out.println("action passing " + pf.getActionAt(innerCounter-1).toCode());
					i++;
					innerCounter++;
				}else if(line.contains(
						getEnd(pf.getActionAt(innerCounter)))){
					i++;
					innerCounter++;
				}
			}
			cutCode = cutCode.substring(cutCode.indexOf("#")+1);
		}
		
		if(isControl){
//			if(innerCounter !=0){
//				innerCounter--;
//			}
//			if(i != 0){
//				i--;
//			}
			System.out.println("recursion " + pf.getActionAt(i).toCode());
			insertCode(allCode.substring(beg, index), ((ControlAction)pf.getActionAt(innerCounter)).getInnerFlow().size(), fa, ((ControlAction)pf.getActionAt(innerCounter)).getInnerFlow(), index-beg);
		}else{
			if(innerCounter !=0){
				innerCounter--;
			}
			System.out.println("pre pf: " + pf.toCode());
			System.out.println("innerCoutner " + innerCounter);
			pf.insertActionAt(innerCounter, fa);
			System.out.println("pst pf: " + pf.toCode());
		}
	}	
	
	public static int findIndex(String allCode, FinchProgramFlow pf, int offset, boolean isControl){
		int i = 0;
		String cutCode = allCode;
		int beg = 0;
		int index = 0;
		int innerCounter = 0;
		
		while(true){
			if(index >= offset){
				offset = index - beg;
				System.out.println("hit caret: " + offset);
				break;
			}
			
			System.out.println("cutCode: " + cutCode);
			String line = cutCode.substring(0, cutCode.indexOf("#")+1);
			index += line.length();
			System.out.println("line: " + line);
			System.out.println("index: " + index + "|offset: "+offset+ "|i = "+i);
			if(line.contains("repeat ")||line.contains("if ")||line.contains("while ")){
//				insertCode(allCode.substring(index, offset), ((ControlAction)pf.getActionAt(i)).getInnerFlow().size(), fa, ((ControlAction)pf.getActionAt(i)).getInnerFlow(), offset);
				System.out.println("isControl = true;");
				beg = index;
				isControl = true;
			}
			
			
			if(line.contains("end")){
				System.out.println("isControl = false;");
				isControl = false;
				i++;
				innerCounter++;
				beg = 0;
			}
			
			if(!isControl){
				if(innerCounter >0 && line.contains(
						getEnd(pf.getActionAt(innerCounter-1)))){
	//				System.out.println("action passing " + pf.getActionAt(innerCounter-1).toCode());
					i++;
					innerCounter++;
				}else if(line.contains(
						getEnd(pf.getActionAt(innerCounter)))){
					i++;
					innerCounter++;
				}
			}
			cutCode = cutCode.substring(cutCode.indexOf("#")+1);
		}
		return i;
	}
	
	
	
	private static void updateEditors(FinchProgramFlow pf){
		CodeEditor codeEditor = (CodeEditor)Application.getInstance().getMainWindow().getFileHost().getCurrentCodeFile().getFileTabbedPane().getComponent(0);
		codeEditor.setUpCodeEditor(pf);
		FlowEditor flowEditor = (FlowEditor)Application.getInstance().getMainWindow().getFileHost().getCurrentCodeFile().getFileTabbedPane().getComponent(1);
		flowEditor.setUpFlowEditor(pf);
		
		Collection<String> fd = FunctionDefinition.getAllFunctionNames();
		for(int i = 0; i < fd.toArray().length; i++){
			System.out.println("registering " + fd.toArray()[i]);
			FunctionDefinition.registerFunction(FunctionDefinition.findFunction((String) fd.toArray()[i]));
		}
		
	}
	
	private static String getEnd(FinchAction fa){
		String endSyn = null;
		String faCode = fa.toCode();
		if(faCode.contains(Move.syntax())){
			endSyn = "move";
		}else if(faCode.contains(TurnLeft.syntax())){
			endSyn = "turnleft";
		}else if(faCode.contains(TurnRight.syntax())){
			endSyn = "turnright";
		}else if(faCode.contains("chirp")){
			endSyn = "chirp";
		}else if(faCode.contains("endif")){
			endSyn = "endif";
		}else if(faCode.contains("repeat")){
			endSyn = "repeat";
		}else if(faCode.contains("endwhile")){
			endSyn = "endwhile";
		}else if(faCode.contains("end")){
			endSyn = "end";
		}else if(faCode.contains("beakcolor")){
			endSyn = "beakcolor";
		}else if(faCode.contains("dropbeeper")){
			endSyn = "dropbeeper";
		}else if(faCode.contains("////*")){
			endSyn = "////*";
		}
		
		return endSyn;
	}
	public static final String replaceNewLines(String s) {
//		s = s.replaceAll("\\n", "#");
//		System.out.println("replaceNL: " + s);
//		return s;
	      StringBuilder result = new StringBuilder();

	      StringTokenizer t = new StringTokenizer(s, "\n");
	      while (t.hasMoreTokens()) {
	          result.append(t.nextToken().trim()).append("#");
	      }
	      return result.toString();
	 }
	public static final String replaceTabs(String s) {
//		s = s.replaceAll("\\t", "#");
//		System.out.println("replaceTabs: " + s);
//		return s;
		StringBuilder result = new StringBuilder();

		StringTokenizer t = new StringTokenizer(s, "\t");
		while (t.hasMoreTokens()) {
			result.append(t.nextToken().trim()).append("#");
		}
		System.out.println("replaceTabs: " + result.toString());
		return result.toString();
	 }
	
}
